<template>
  <div class="chat-container">
    <!-- 房间列表 -->
    <div class="left" ref="leftRef">
      <div class="top-box">
        <!-- 搜索 -->
        <div class="search">
            <el-input
              v-model="roomKw"
              clearable
              placeholder="搜索"
              :prefix-icon="Search"
              @keyup.enter="getRoomList"
            />
        </div>
        <!-- 创建群聊 -->
        <div class="create-group" @click="openEditGroupComponent = true">
          <el-icon><Plus/></el-icon>
        </div>
      </div>

      <!-- room -->
      <div class="room-list beautify-scrollbar">
        <room-item 
          v-for="item in roomList" 
          :key="item.id" 
          :room="item"
          @click="handleRoomItemClick(item)"
        />
      </div>

    </div>

    <!-- 拖动捕捉区 -->
    <div class="resizer" @mousedown="startResize"></div>

    <!-- 聊天区域 -->
    <div class="right" v-if="RoomState.currentRoom.id">
      <!-- 标题区 -->
      <div class="title-box">
        <div class="chat-title private-chat-title" v-if="RoomState.currentRoom.roomType===1">
          <div class="up">
            <strong>{{ RoomState.currentRoom.roomName }}</strong>
          </div>
          <div class="down">
            <span class="state" 
              :style="{backgroundColor: stateTipBgc}"
            ></span>
            <span class="dept-job">
              {{ chatUserDeptJob }}
            </span>
          </div>
        </div>
        <div class="chat-title group-chat-title" v-if="RoomState.currentRoom.roomType===2">
          
          <!-- 
          通过动态组件实现：正常以span展示群组名，当点击时切换为el-input组件进行编辑群组名
          1. :is后面的是组件名或者DOM名称，注意需要用单引号
          2. v-bind动态绑定的是组件或者DOM本身的属性
          3. @可以给组件绑定函数
          4. 当组件内部的DOM较多时，通过innerHTML不好写，则可以用<component>...innerHTML...</component>的写法
          -->
          <component 
            :is="isEditGroupName ? 'ElInput' : 'span'"
            v-bind="groupNameDomProps"
            @click="handleClickGroupName"
            @blur="doSubmitEditGroupName"
            @keyup.enter="doSubmitEditGroupName"
          />
        </div>
      </div>

      <!-- 消息区 -->
      <div class="message-box">
        <div class="loading" v-if="loading">loading...</div>
        <div class="chat-message-box beautify-scrollbar" 
            style="overflow-x: hidden;" 
            ref="chatMsgBoxRef" 
            @scroll="onScroll"
        >
          
          <!-- 消息项（改为使用<msg-item组件>） -->
          <!-- 
          <div class="msg-item" v-for="msg in msgList" :key="msg.id">
            <div class="title"
              v-if="msg.msgType != 0"
              :style="{flexDirection: msg.sentBy!=UserState.loginUser.id ? 'row' : 'row-reverse'}"
            >
              <div class="user"><strong>{{ msg.sentByName }}</strong></div>
              <div class="time">{{ DateFormatter.format(new Date(msg.sentAt), 'yy-MM-dd HH:mm') }}</div>
            </div>
            <div class="content"
              :style="{flexDirection: msg.sentBy!=UserState.loginUser.id ? 'row' : 'row-reverse'}"
              v-if="msg.msgType != 0"
            >
              <div class="content-detail" v-html="msg.content"
                :style="{backgroundColor: msg.sentBy!=UserState.loginUser.id ? '#FFEBCD' : '#C9E7FF'}"
                @contextmenu="handleMsgRightClick($event, msg)"
                @click="handleClickMsgContent(msg)"
                ></div>
            </div>
            <div class="sys-msg-content" v-if="msg.msgType === 0">
              <span>{{ msg.content }}</span>
            </div>
            <div class="quote-msg-content"
              :style="{flexDirection: msg.sentBy!=UserState.loginUser.id ? 'row' : 'row-reverse'}"
              v-if="JSON.parse(msg.extData) && JSON.parse(msg.extData).hasQuoteMsg"
            >
              <el-popover 
                placement="right" 
                trigger="click"
                width="auto"
                :enterable="true"
                v-if="JSON.parse(msg.extData).quoteMsg.msgType===1"
              >
                <template #reference>
                  <span class="quote-content-detail ellipsis-text" v-html="JSON.parse(msg.extData).quoteMsgHtml"></span>
                </template>
                <div v-html="JSON.parse(msg.extData).quoteMsg.content"></div>
              </el-popover>
              <span v-else 
                class="quote-content-detail" 
                v-html="JSON.parse(msg.extData).quoteMsgHtml"
                @click="handleClickQuoteMsgBox2"
              ></span>
            </div>
          </div> 
          -->

          <msg-item
            v-for="msg in msgList"
            :key="msg.id"
            :msg="msg"
            :justify-type="msg.sentBy===UserState.loginUser.id ? 'right' : 'left'"
            :msg-bg-color="msg.sentBy===UserState.loginUser.id ? '#C9E7FF' : '#fff'"
            user-color="gray"
            :show-send-time="true"
            send-time-format="HH:mm"
            @click-msg="handleClickMsgContent"
            @click-quote-msg="handleClickQuoteMsgContent"
            @right-click-msg="handleMsgRightClick"
          /> 

        </div>
        <div class="tip-box" v-if="!isAtBottom && newMsgCount > 0" @click="scrollToBottom">
          <el-icon><ArrowDown /></el-icon>{{ newMsgCount }}条新消息
        </div>
      </div>

      <!-- 输入框拖动器 -->
      <div class="v-resizer" @mousedown="startIbResize"></div>
      
      <!-- 输入区 -->
      <div class="input-box" ref="ibRef">

        <!-- 顶部菜单列 -->
        <div class="menu-list-box">
          <div class="btn-box left-btn">
            <div class="item">
              <el-tooltip
                effect="dark"
                content="截图"
                placement="top"
              >
                <span style="font-size: 17px;" class="iconfont icon-jietu el-icon" @click="openScreenShot"></span>
              </el-tooltip>
            </div>
            <div class="item">
              <el-tooltip
                effect="dark"
                content="文件"
                placement="top"
              >
                <el-upload
                  :action="AttachmentApi.upload"
                  multiple
                  name="file"
                  :show-file-list="false"
                  :headers="fileUploadHeaders"
                  :data="fileUploadExtData"
                  :on-success="handleFileUploadSuccess"
                >
                  <el-icon><FolderOpened /></el-icon>
                </el-upload>
              </el-tooltip>
            </div>
            <div class="item" v-if="RoomState.currentRoom.isMuted===1">
              <el-tooltip
                effect="dark"
                content="新消息提醒"
                placement="top"
              >
                <el-icon @click="updateRoomMuted"><Bell /></el-icon>
              </el-tooltip>
            </div>
            <div class="item" v-if="RoomState.currentRoom.isMuted===0">
              <el-tooltip
                effect="dark"
                content="消息免打扰"
                placement="top"
              >
                <el-icon @click="updateRoomMuted"><MuteNotification /></el-icon>
              </el-tooltip>
            </div>
            <div class="item">
              <el-tooltip
                effect="dark"
                content="聊天记录"
                placement="top"
              >
                <el-icon @click="showChmDrawer"><ChatDotRound /></el-icon>
              </el-tooltip>
            </div>
            <div class="item" v-if="RoomState.currentRoom.roomType===2">
              <el-tooltip
                effect="dark"
                content="群成员"
                placement="top"
              >
                <el-icon @click="showGroupUserDrawer"><User /></el-icon>
              </el-tooltip>
            </div>
            <div class="item" v-if="RoomState.currentRoom.roomType===2">
              <el-tooltip
                effect="dark"
                content="群公告"
                placement="top"
              >
                <el-icon @click="openRoomBulletinDrawer = true"><Memo /></el-icon>
              </el-tooltip>
            </div>
          </div>
          <div class="btn-box right-btn">
            <el-button type="primary" size="small" @click="sendMessage">发送</el-button>
          </div>
        </div>

        <!-- 引用消息区 -->
        <div class="quote-msg-box" v-if="quoteMsg">
          <span class="ellipsis-text" ref="quoteMsgBoxRef" @click="handleClickQuoteMsgBox" v-html="quoteMsgHtml"></span>
          <el-icon @click="quoteMsg = null"><Close /></el-icon>
        </div>

        <!-- 消息输入框 -->
        <div class="message-input-box">
          <el-input
            v-model="message"
            ref="messageRef"
            type="textarea"
            show-word-limit
            style="height: 100%;"
            @keyup.enter="sendMessage"
            @paste.prevent="handlePaste"
          />
        </div>
      </div>
    </div>

    <!-- 创建群聊弹框 -->
    <edit-group 
      v-model:visible="openEditGroupComponent"
      v-model:mode="editGroupComponentMode"
      :users="groupUserList"
    />

    <!-- 群成员抽屉框 -->
    <el-drawer class="group-user-drawer" 
      v-model="openGroupUserDrawer" 
      @close="closeGroupUserDrawer"
      :modal="false"
    >
      <template #header>
        <h4>群成员({{ groupUserList.length }})</h4>
      </template>
      <template #default>
        <div class="group-user-container">
          <div class="group-user-list beautify-scrollbar">
            <div class="item" v-for="user in groupUserList" :key="user.id">
                <div class="user-info">
                    <div class="left">
                      <lc-avatar class="lc-avatar" :src="user.avatar"/>
                      <span>{{ user.username }}</span>
                    </div>
                    <div class="right">
                      <span @click="doRemindUser(user)" class="item tip-opt" v-if="user.id != UserState.loginUser.id">@</span>
                      <el-tooltip
                        effect="dark"
                        content="发送消息"
                        placement="top"
                        v-if="user.id != UserState.loginUser.id"
                      >
                        <el-icon @click="sengMsgToUser(user)" class="item send-msg"><ChatLineRound/></el-icon>
                      </el-tooltip>
                      <el-tooltip
                        effect="dark"
                        content="查看资料"
                        placement="top"
                      >
                        <el-icon @click="catUserInfo(user)" class="item user-info"><User/></el-icon>
                      </el-tooltip>
                    </div>
                </div>
            </div>
          </div>
        </div>
        
      </template>
      <template #footer>
        <div style="flex: auto">
          <el-button size="small" type="warning" @click="quitGroup">退出群聊</el-button>
          <el-button size="small" type="success" @click="showAddGroupUserDialog">邀请成员</el-button>
        </div>
      </template>
    </el-drawer>



    <!-- 聊天记录抽屉框 -->
    <el-drawer class="chm-drawer" 
      v-model="openChmDrawer" 
      @close="closeChmDrawer"
      :modal="false"
      :with-header="false"
      size="40%"
    >
    <div class="chm-container">
      <div class="custom-header">
        <div class="up">
          <el-input
            v-model="chmQo.kw"
            placeholder="搜索"
            :prefix-icon="Search"
            size="small"
            clearable
          />
          <el-icon @click="openChmDrawer=false"><CloseBold /></el-icon>
        </div>
        <div class="down">
          <span class="item" 
            :style="{backgroundColor: chmQo.msgType==='3,5'?'lightblue':'transparent'}"
            @click="chmQo.msgType==='3,5' ? chmQo.msgType = '' : chmQo.msgType = '3,5'"
          >文件</span>
          <span class="item"
            :style="{backgroundColor: chmQo.msgType==='2,4'?'lightblue':'transparent'}"
            @click="chmQo.msgType==='2,4' ? chmQo.msgType = '' : chmQo.msgType = '2,4'"
          >图片/视频</span>
          <span class="item"
            :style="{backgroundColor: chmQo.msgType==='6'?'lightblue':'transparent'}"
            @click="chmQo.msgType==='6' ? chmQo.msgType = '' : chmQo.msgType = '6'"
          >链接</span>
          <el-date-picker
            v-model="chmQo.startTime"
            type="date"
            style="max-width: 100px;"
            placeholder="开始日期"
            size="small"
            format="YYYY/MM/DD"
            value-format="YYYY-MM-DD"
          />
          <el-date-picker
            v-model="chmQo.endTime"
            type="date"
            style="max-width: 100px;"
            placeholder="结束日期"
            size="small"
            format="YYYY/MM/DD"
            value-format="YYYY-MM-DD"
          />
        </div>
      </div>
      <div class="chm-list beautify-scrollbar"
        ref="chmListBoxRef"
      >
        <msg-item
          v-for="msg in chmList"
          :key="msg.id"
          :msg="msg"
          :show-send-time="true"
          :user-color="msg.sentBy===UserState.loginUser.id ? '#FF6347' : 'gray'"
        />  

      </div>
    </div>
    </el-drawer>



    <!-- 群公告抽屉框 -->
    <el-drawer class="room-bulletin-drawer" 
      v-model="openRoomBulletinDrawer"
      title="群公告"
      size="40%"
      :modal="false"
    >
      <div class="room-bulletin-container">
        <div v-html="RoomState.currentRoom.roomBulletin" class="room-bulletin beautify-scrollbar" @click="handleRbDrawerClick"></div>
      </div>
      <template #footer>
        <div style="flex: auto">
          <el-button size="small" type="warning" @click="showRbEditDialog">编辑</el-button>
        </div>
      </template>
    </el-drawer>


    <!-- 群公告编辑对话框 -->
    <el-dialog
      class="rb-edit-dialog"
      v-model="isRbdEdit"
      :show-close="false"
      :draggable="true"
      :modal="false"
    >
      <!-- 自定义头部，对象解构赋值具名插槽传递的参数 -->
      <template #header="{ close, titleId, titleClass }">
        <div class="rb-edit-dialog-header">
          <div :id="titleId" :class="titleClass">编辑群公告</div>
          <div class="btn">
            <span style="color: blue;" class="iconfont icon-baocun1" @click="doSaveRbEdit"></span>
            <span style="color: red;font-size: 20px;" class="iconfont icon-shanchu" @click="close"></span>
          </div>
        </div>
      </template>
      <div class="rb-edit-container">
        <editor v-model:content="rbText"/>
      </div>
    </el-dialog>


    <!-- 图片预览 -->
    <!-- 
    1. url-list: 预览的图片链接列表
    2. initial-index: 初始预览图像索引，小于 url-list 的长度
    3. infinite: 是否可以无限循环预览
    4. @close: 当点击 X 按钮或者在hide-on-click-modal为 true 时点击遮罩层时触发
    -->
    <el-image-viewer
      v-if="showImageViewer"
      :url-list="urlList"
      :initial-index="initialIndex"
      :infinite="false"
      @close="closeImageViewer"
    />

    <!-- 右击消息菜单 -->
    <div class="rc-msg-menu"
      ref="rcMsgMenuRef"
      v-if="rcMsgMenuVisible"
      :style="{left: `${rcMsgMenuPosition.x}px`, top: `${rcMsgMenuPosition.y}px`}"
    >
      <div class="rc-msg-menu-item" @click="handleMsgQuote">
          引用
      </div>
      <div class="rc-msg-menu-item" @click="handleMsgCopy">
          复制
      </div>
      <div 
        class="rc-msg-menu-item" @click="handleFileSaveAs"
        v-if="rcMsg && JSON.parse(rcMsg.extData).mediaType"
      >
          另存为
      </div>
    </div>

    <!-- 个人资料 -->
    <personal-data
      title="用户信息"
      v-model:visible="personalDataVisible"
      :user="toCatUser"
    />

    <!-- 截图 -->
    <screen-short
      v-if="screenshotStatus"
      @get-image-data="getImg"
      @destroy-component="destroyComponent"
    >
    </screen-short>

  </div>
</template>


<script setup>
// 导入
import { ref,onMounted,onBeforeUnmount,nextTick,watch,computed } from 'vue'
import { $get,$post } from '@/utils/request';
import { AttachmentApi, RoomApi,MessageApi } from '@/api/path';
import { $msg_e,$msg_i,$msg_s,$msg_w } from '@/utils/msg';
import RoomItem from './RoomItem.vue';
import EditGroup from './EditGroup.vue'
import DateFormatter from '@/utils/dateFormatter';
import { RoomState } from '@/store/currentRoom';
import { UserState } from '@/store/loginUser';
import LcAvatar from './LcAvatar.vue';
import PersonalData from './PersonalData.vue';
import MsgItem from './MsgItem.vue';
import Editor from './Editor.vue';
import { 
  Plus,
  FolderOpened,
  Bell,
  MuteNotification,
  ChatDotRound,
  User,
  ChatLineRound,
  Memo,
  Close,
  CloseBold,
  Search,
  ArrowDown } from '@element-plus/icons-vue';


// 左侧聊天室左右拖动变量
const leftRef = ref(null)
let isResizing = false;
let initialWidth = 0;
let initialX = 0;

// 底部输入框上下拖动变量
const ibRef = ref(null)
let isIbResizing = false;
let ibInitialHeight = 0;
let ibInitialY = 0;

// 聊天实列表数据
const roomKw = ref('')
const roomMap = ref(new Map())
const roomList = computed(() => {
  const arr = Array.from(roomMap.value.values())
  arr.sort((a,b) => {
    const timeA = a.lastMsgAt ? new Date(a.lastMsgAt).getTime() : -Infinity;
    const timeB = b.lastMsgAt ? new Date(b.lastMsgAt).getTime() : -Infinity;
    return timeB - timeA;
  })
  return arr
})


// 显示创建群聊组件
const openEditGroupComponent = ref(false)
const editGroupComponentMode = ref('')

// 聊天室标题区
const stateTipBgc = computed(() => {
  return RoomState.currentRoom 
        && RoomState.currentRoom.roomType
        && RoomState.currentRoom.roomType===1
        && RoomState.currentRoom.extData.status===1 ? '#00FF00' : '#DCDCDC'
})
const chatUserDeptJob = computed(() => {
  if(RoomState.currentRoom 
        && RoomState.currentRoom.roomType
        && RoomState.currentRoom.roomType===1){
          let arr = []
          let deptName = RoomState.currentRoom.extData.deptName
          let job = RoomState.currentRoom.extData.job
          if(deptName) arr.push(deptName);
          if(job) arr.push(job)
          return arr.join('-')
        }
  return ''
})
const isEditGroupName = ref(false)
const newGroupName = ref('')
// 动态属性绑定
const groupNameDomProps = computed(() => {
  return isEditGroupName.value ? 
        {
          // el-input的属性
          modelValue: newGroupName.value, // 传递给 ElInput 的值
          'onUpdate:modelValue': (value) => { newGroupName.value = value }, // 处理更新
          style: 'width: 200px',
          clearable: true
        } :
        {
          // span的属性
          style: 'font-size: 14px;font-weight: bold;',
          innerText: RoomState.currentRoom.roomName
        }
})


// 输入框数据
const message = ref('')
const messageRef = ref(null)
const setMessageInputFocus = () => {
  if(messageRef.value){
    messageRef.value.focus()
  }
}

// 聊天消息滚动框数据
const maxLength = 20;
const msgList = ref([])
const chatMsgBoxRef = ref(null)
const isAtBottom = ref(true)
const newMsgCount = ref(0)
const loading = ref(false)

// 文件上传数据
const fileUploadHeaders = ref({
    'x-auth-token':window.localStorage.getItem('token')
})
const fileUploadExtData = ref({
    bizType: 'chat_file',
    bizId: RoomState.currentRoom.id + ',' + UserState.loginUser.id 
})


// 群成员
const groupUserList = ref([])
const openGroupUserDrawer = ref(false)


// 图片预览数据
const showImageViewer = ref(false)
const urlList = ref([])
const initialIndex = ref(0)
const previewOneImage = url => { // 预览一张图片
  urlList.value = [url]
  showImageViewer.value = true
}



// 左侧聊天室左右拖动函数
const startResize = (e) => {
    isResizing = true;
    initialX = e.clientX; // 鼠标相对与浏览器左上角的x坐标
    initialWidth = leftRef.value.offsetWidth; // 获取元素的布局宽度（包括内边距、边框和垂直滚动条，但不包括外边距）
    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', stopResize);
};
const onMouseMove = (e) => {
    if (isResizing) {
        const deltaX = e.clientX - initialX;
        let newWidth = initialWidth + deltaX;
        // 限制最小宽度
        newWidth = newWidth < 150 ? 150 : (newWidth > 350 ? 350 : newWidth)
        leftRef.value.style.width = `${newWidth}px`;
    }
};
const stopResize = () => {
    isResizing = false;
    document.removeEventListener('mousemove', onMouseMove);
    document.removeEventListener('mouseup', stopResize);
};


// 底部输入框上下拖动函数
const startIbResize = (e) => {
    isIbResizing = true;
    ibInitialY = e.clientY; 
    ibInitialHeight = ibRef.value.offsetHeight; 
    document.addEventListener('mousemove', ibOnMouseMove);
    document.addEventListener('mouseup', stopIbResize);
};
const ibOnMouseMove = (e) => {
    if (isIbResizing) {
        const deltaY = ibInitialY - e.clientY;
        let newHeight = ibInitialHeight + deltaY;
        // 限制最小宽度
        newHeight = newHeight < 200 ? 200 : (newHeight > 400 ? 400 : newHeight)
        ibRef.value.style.height = `${newHeight}px`;
    }
};
const stopIbResize = () => {
    isIbResizing = false;
    document.removeEventListener('mousemove', ibOnMouseMove);
    document.removeEventListener('mouseup', stopIbResize);
};


// 获取聊天室列表
const getRoomList = async () => {
  const res = await $get(RoomApi.getList, {kw: roomKw.value});
  // console.log('getRoomList-res:',res);
  if(!res.success){
    return $msg_e(res.message)
  }
  // 将 list 转换为 Map，以 id 为键
  // roomMap.value = new Map(res.data.map(room => [room.id, room]));

  // 下面的方法也可
  // 清空 Map 以避免累积旧数据
  roomMap.value.clear();

  // 将接口返回的 list 数据以 id 为键，room 为值存入 Map
  const cachedRoomId = RoomState.currentRoom.id
  res.data.forEach(room => {
    if(room.id===cachedRoomId){
      setToCurRoom(room) // 重置当前聊天室
    }
    roomMap.value.set(room.id, room);
  });

  if(!roomMap.value.has(cachedRoomId)){
    RoomState.setCurrentRoom({})
  }
}


// 点击聊天室
const handleRoomItemClick = async room => {
  setToCurRoom(room)
  setMessageInputFocus()
}

const setToCurRoom = room => {
  RoomState.setCurrentRoom(room)
  // 未读消息重置为0
  room.unreadMsgCount = 0
  // 查询房间的最新消息
  initLoadChatMsg()
}

// 发送文件消息
const sendFileMessage = (data, file) => {
  // console.log('sendFileMessage-file: ', file);
  let previewUrl = data.previewUrl
  let downloadUrl = data.downloadUrl
  let mediaType = file.type
  let fileName = file.name
  const msg = {
    roomId: RoomState.currentRoom.id,
    msgType: toFileMsgType(mediaType),
    content: toFileMsgContent(mediaType, fileName, previewUrl, downloadUrl),
    simpleText: toFileMsgSimpleText(mediaType, fileName),
    sentBy: UserState.loginUser.id,
    sentByName: UserState.loginUser.username,
    sentAt: DateFormatter.toSimpleISOString(),
    extData: JSON.stringify({previewUrl,downloadUrl,fileName,mediaType,hasQuoteMsg:false})
  }

  // console.log('sendFileMessage-msg: ', msg);

  // 发送socket
  window.socket.emit('message', msg);
}

const toFileMsgType = mediaType => {
  if(mediaType.startsWith('image')) return 2; // 图片
  if(mediaType.startsWith('audio')) return 3; // 音频
  if(mediaType.startsWith('video')) return 4; // 视频
  return 5; // 文件
}

const toFileMsgContent = (mediaType,fileName,previewUrl,downloadUrl) => {
  // 注意v-html中渲染的是HTML标签，而不是vue组件，故不能用<el-image>等标签
  if(mediaType.startsWith('image')) {
    return `<img style='width: 200px;' src='${previewUrl}'/>`
  }
  // 暂时不做音频的预览，默认以文件的形式展示
  // if(mediaType.startsWith('audio')) {
  //   return `<audio controls style='width: 200px;height: 30px;' src='${previewUrl}'>`
  // }
  if(mediaType.startsWith('video')) {
    return `<video controls style='width: 200px' src='${previewUrl}'/>`
  }
  return `<a href='${downloadUrl}' download='${fileName}'>${fileName}</a>`
}

const toFileMsgSimpleText = (mediaType,fileName) => {
  if(mediaType.startsWith('image')) return `[图片]${fileName}`;
  // if(mediaType.startsWith('audio')) return `[音频]${fileName}`;
  if(mediaType.startsWith('video')) return `[视频]${fileName}`;
  return `[文件]${fileName}`;
}




// 发送消息
const sendMessage = (event) => {
  // 检查是否按下了 Shift 键，如果按下 Shift 键则不触发事件
  if (event.shiftKey) return;
  let content = message.value;

  // 截取掉最后一个回车符
  let index = content.lastIndexOf('\n');
  if (index !== -1) {
    content = content.substring(0, index);
  }

  if(!content){
    $msg_w('不能发送空白消息');
    message.value = ''
    return
  } 

  if(content.length > 2000){
    message.value = ''
    return $msg_w('超出2000字符数限制，请复制到文件中发送')
  }
  
  const obj = checkUrl(content)

  // 发送到socket
  const msg = {
    roomId: RoomState.currentRoom.id,
    msgType: obj.hasValidURL ? 6 : 1,
    content: obj.updatedText,
    simpleText: toSimpleText(message.value), // 生成房间的最后一条消息
    sentBy: UserState.loginUser.id,
    sentByName: UserState.loginUser.username,
    sentAt: DateFormatter.toSimpleISOString(),
    extData: JSON.stringify(buildExtData())
  }

  // console.log('message: ', msg);
  window.socket.emit('message', msg)

  // 清空引用内容和输入框
  quoteMsg.value = null
  message.value = ''
  
}

const checkUrl = text => {
  const urlRegex = /https?:\/\/[^\s/$.?#].[^\s]*/gi;  // 匹配 http 或 https 开头的 URL
  const matches = text.match(urlRegex);  // 获取所有匹配的 URL
  
  // 判断是否包含有效的 URL
  const hasValidURL = matches && matches.length > 0;

  // 替换文本中的 URL 为 <a> 标签
  const updatedText = text.replace(urlRegex, (url) => {
    return `<a href='${url}' target='_blank'>${url}</a>`;
  });

  return { updatedText, hasValidURL };
}

const buildExtData = () => {
  return {
    hasQuoteMsg: quoteMsg.value ? true : false,
    quoteMsg: quoteMsg.value ? quoteMsg.value : {},
    quoteMsgHtml: quoteMsgHtml.value
  }
}


// 房间的最后一条消息
const toSimpleText = message => {
  return message.trim().slice(0, 300);
}


// 粘贴事件
const handlePaste = async event => {
  // 获取剪贴板中的项目
  const items = event.clipboardData.items
  console.log('paste: ', items)
  if(items.length <= 0) return;
  const item = items[0]

  // console.log('paste-item: ', item)
  // console.log('item.type: ' + item.type) // image/jpeg
  // console.log('item.kind: ' + item.kind) // file

  // 处理文件上传
  if(item.kind === 'file'){
    const file = item.getAsFile()
    console.log('file.raw.type: ', file);
    const formData = new FormData()
    formData.append('file', file)
    formData.append('bizType', 'chat_file')
    formData.append('bizId', RoomState.currentRoom.id + ',' + UserState.loginUser.id)
    const res = await $post(AttachmentApi.upload, formData, {
      headers:{
        'Content-Type': 'multipart/form-data',
        'x-auth-token':window.localStorage.getItem('token')
      }
    })
    console.log('paste-upload-res: ', res)
    if(!res.success){
      return $msg_e(res.message)
    }
    sendFileMessage(res.data, file)
  }

  // 处理文本
  if(item.kind === 'string'){
    // 如果是纯文本（非文件和图片）
    const text = event.clipboardData.getData('text')
    if (text) {
      // console.log('粘贴的文本内容:', text)
      message.value += text
    }
  }
}


// 查询聊天记录
const getChatMessage = async params => {
  const res = await $get(MessageApi.getChatHistory, params);
  // console.log('getChatMessage-res: ', res);
  if(!res.success){
    $msg_e(res.message)
    return []
  }
  return res.data
}


// 聊天消息滚动框函数
const appendChatMsg = msg => {
    msgList.value.push(msg)// 追加到消息列表
    if(isAtBottom.value){
        // 删除头部元素直到数组长度不超过 maxLength
        if (msgList.value.length > maxLength) {
            msgList.value.splice(0, msgList.value.length - maxLength);
        }
        // 确保视图更新后再滚动到底部
        nextTick(() => {
            scrollToBottom();
        });
    }else{
        newMsgCount.value++
    }
}

/**
 * 初始化加载聊天记录
 */
const initLoadChatMsg = async () => {
    let curRoom = RoomState.currentRoom
    if(!curRoom || !curRoom.id){
      return;
    }
    const params = {
      roomId: curRoom.id,
      pageSize: maxLength
    }
    let ml = await getChatMessage(params);
    msgList.value = ml.reverse();// 反转数组
    scrollToBottom()
}


const loadChatHistoryInMsgBox = async () => {
    const cmb = chatMsgBoxRef.value
    const oldHeight = cmb.scrollHeight;
    // console.log("oldHeight: " + oldHeight);

    // 设置 loading 为 true，显示 loading 图标
    loading.value = true;
    
    const params = {
      roomId: RoomState.currentRoom.id,
      pageSize: maxLength
    }
    if(msgList.value.length > 0){
      params.prePageLastId = msgList.value[0].id
    }
    let ml = await getChatMessage(params);
    let ml2 = ml.reverse()
    // 从头部添加数组
    msgList.value.unshift(...ml2)
    
    // 等待DOM渲染完后再获取新高度
    nextTick(() => {
        // console.log('msgListCount: ' + msgList.value.length);
        const newHeight = cmb.scrollHeight;
        // console.log('newHeight: ' + newHeight);
        cmb.scrollTop = newHeight - oldHeight - 100

        // 请求完成后，设置 loading 为 false，隐藏 loading 图标
        loading.value = false;
    })
}

// 消息点击事件
const handleClickMsgContent = msg => {
  // 只处理图片预览
  if(msg.msgType != 2){
    return
  }

  // 提取当前聊天框的消息缓存列表
  const picImgUrls = msgList.value.filter(msg => msg.msgType===2).map(msg => {
    const extDataJson = JSON.parse(msg.extData)
    return extDataJson.previewUrl
  })

  // 找出当前双击的图片在图片列表中的索引
  const curPicExtData = JSON.parse(msg.extData);
  const curPicUrl = curPicExtData.previewUrl
  const curPicIndex = picImgUrls.indexOf(curPicUrl)

  urlList.value = picImgUrls
  initialIndex.value = curPicIndex < 0 ? 0 : curPicIndex
  showImageViewer.value = true

}

// 处理引用消息点击事件
const handleClickQuoteMsgContent = msg => {
  // 只处理图片预览
  if(msg.msgType != 2){
    return
  }

  // 找出当前双击的图片在图片列表中的索引
  const curPicExtData = JSON.parse(msg.extData);
  const curPicUrl = curPicExtData.previewUrl
  previewOneImage(curPicUrl);
}

const closeImageViewer = () => {
  // console.log('closeImageViewer');
  urlList.value = []
  initialIndex.value = 0
  showImageViewer.value = false
}

/**
 * 聊天框滚动到最底部
 */
const scrollToBottom = async () => {
  // Vue 会异步地更新 DOM，以提高性能
  // 如需要在数据更新后立即访问最新的 DOM 状态，就需要用 $nextTick 来确保 DOM 更新已经完成
  newMsgCount.value = 0
  nextTick(()=>{
    const cmb = chatMsgBoxRef.value;
    if(!cmb) return;
    // 滚动到底部
    // cmb.scrollTop = cmb.scrollHeight - cmb.clientHeight
    cmb.scrollTop = cmb.scrollHeight
  })

  // 设置已读
  const params = {
    roomId: RoomState.currentRoom.id,
    readAt: DateFormatter.toSimpleISOString()
  }
  const res = await $post(MessageApi.setReadByRoomId, params)
  console.log('setReadByRoomId-res:', res);
  if(!res.success){
    $msg_e(res.message)
  }
}

/**
 * 聊天框滚动监听事件
 */
const onScroll = () => {
    const cmb = chatMsgBoxRef.value;
    if(!cmb) return;
    let t = cmb.scrollTop
    let c = cmb.clientHeight
    let h = cmb.scrollHeight
    // console.log('scrollTop: ' + t);
    // console.log('clientHeight: ' + c);
    // console.log('scrollHeight: ' + h);
    const tolerance = 1; // 容忍误差1px（由于 浏览器渲染的细微精度差异 和 浮动小数点误差，可能会小0.5px的误差）
    if(t + c >= h - tolerance){
        // console.log('toBottom');
        isAtBottom.value = true
        newMsgCount.value = 0
    }else{
        isAtBottom.value = false
    }
    if(t === 0){
        // console.log('toTop');
        loadChatHistoryInMsgBox()
    }
}




// 文件上传
const handleFileUploadSuccess = (res, file, fileList) => {
    // console.log('handleFileUploadSuccess-res: ', res);
    // console.log('handleFileUploadSuccess-file: ', file);
    // console.log('fileType: ' + file.raw.type); // 媒体类型，开头：image-图片，video-视频
    sendFileMessage(res.data, file.raw)
}


// 点击群民事件
const handleClickGroupName = () => {
  if(isEditGroupName.value){
    return
  }
  newGroupName.value = RoomState.currentRoom.roomName
  isEditGroupName.value = true
}

// 提交编辑群组名
const doSubmitEditGroupName = async () => {
  if(!newGroupName.value){
    isEditGroupName.value = false
    return
  }
  if(newGroupName.value.length > 30){
    return $msg_e('群组名称字符数不能超过30')
  }
  let params = {
    roomId: RoomState.currentRoom.id,
    roomName: newGroupName.value
  }
  const res = await $post(RoomApi.updById, params);
  if(!res.success){
    $msg_e(res.message)
  }else{
    RoomState.currentRoom.roomName = params.roomName
  }
  isEditGroupName.value = false
}

// 修改消息免打扰状态
const updateRoomMuted = async () => {
  let params = {
    roomId: RoomState.currentRoom.id,
    isMuted: RoomState.currentRoom.isMuted===0 ? 1 : 0
  }
  const res = await $post(RoomApi.setMuted, params)
  if(!res.success){
    return $msg_e(res.message)
  }
  RoomState.currentRoom.isMuted = params.isMuted
}

// 群成员函数
const showGroupUserDrawer = async () => {
  let params = {roomId: RoomState.currentRoom.id}
  const res = await $get(RoomApi.getUsers, params)
  if(!res.success){
    return $msg_e(res.message)
  }
  groupUserList.value = res.data
  openGroupUserDrawer.value = true
}
const closeGroupUserDrawer = () => {
  groupUserList.value = []
}
const quitGroup = async () => {
  const res = await $post(RoomApi.quitRoom, {roomId: RoomState.currentRoom.id})
  // console.log('quitGroup-res:',res);
  if(!res.success){
    return $msg_e(res.message)
  }
  $msg_s('退出群聊成功')
  openGroupUserDrawer.value = false
  getRoomList()
}
const showAddGroupUserDialog = () => {
  openEditGroupComponent.value = true
  editGroupComponentMode.value = 'edit'
}
const sengMsgToUser = async user => {
  // console.log('sengMsgToUser-user: ', user);
  const res = await $post(RoomApi.createRoom,[user.id]);
  // console.log('createPrivateRoom-res: ', res);
  if(!res.success){
    return $msg_e(res.message)
  }
  RoomState.setCurrentRoom(res.data)
  openGroupUserDrawer.value = false
}

const toCatUser = ref({})
const personalDataVisible = ref(false)
const catUserInfo = user => {
  // console.log('catUserInfo-user:', user);
  toCatUser.value = user
  personalDataVisible.value = true
}


// 处理message事件消息
const handleSocketMessageEventMsg = async msg => {
  handleNewMsgBrowserNotify(msg)
  // 1. 更新当前聊天框中的消息
  let isCurRoom = RoomState.currentRoom && RoomState.currentRoom.id && msg.roomId===RoomState.currentRoom.id
  if(isCurRoom){
    appendChatMsg(msg)
  }

  // 2. 更新聊天室列表中的信息
  let cr;
  if(roomMap.value.has(msg.roomId)){
    cr = roomMap.value.get(msg.roomId)

    // 未读消息计数
    if(msg.type != 0){
      if(!isCurRoom || !isAtBottom.value){
        cr.unreadMsgCount += 1
        UserState.unreadCountIncrease()
      }
    }

    cr.lastMsg = msg.simpleText
    cr.lastMsgAt = msg.sentAt
    cr.lastMsgSentBy = msg.sentBy
    cr.lastMsgSentByName = msg.sentByName

  } else { // 不在列表中
    const res = await $get(RoomApi.getDetail, {id: msg.roomId})
    if(res.success){
      cr = res.data
      roomMap.value.set(cr.id, cr)
    } else{
      throw new Error('干! 查询不到聊天室! 隐身了?!' + res.message);
    }
  }

  // 3. 设置当前聊天室
  if(!RoomState.currentRoom && !RoomState.currentRoom.id){
    setToCurRoom(cr)
  }
}

// 处理state事件消息
const handleSocketStateEventMsg = msg => {
  let curRoom = RoomState.currentRoom;
  if(!curRoom || !curRoom.id || curRoom.roomType!=1){
    return;
  }
  if(msg.userId === curRoom.extData.id){
    let userStatus = msg.userStatus==='ONLINE' ? 1 : 0;
    curRoom.extData.status = userStatus
  }
}

// 更新群名
const handleSocketUpdGroupNameEventMsg = msg => {
  let roomId = msg.roomId
  let roomName = msg.roomName
  for (const room of roomMap.value.values()) {
    if (room.id === roomId) {
      room.roomName = roomName
      return;
    }
  }
}


// 初始化socket监听事件
const initSocketListener = () => {
  window.socket.on('message', msg => {
    console.log('监听message事件接收到消息: ', msg);
    handleSocketMessageEventMsg(msg)
  })

  window.socket.on('state', msg => {
    console.log('监听state事件接收到消息: ', msg);
    handleSocketStateEventMsg(msg)
  })

  window.socket.on('upd_group_name', msg => {
    console.log('监听upd_group_name事件接收到消息: ', msg);
    handleSocketUpdGroupNameEventMsg(msg)
  })
}



// 右击消息数据
const rcMsg = ref(null)
const rcMsgMenuRef = ref(null)
const rcMsgMenuVisible = ref(false)
const rcMsgMenuPosition = ref({
    x: 0,
    y: 0
})
const quoteMsg = ref(null)
const quoteMsgHtml = computed(() => {
  if(!quoteMsg.value){
    return ''
  }
  const sentByName = quoteMsg.value.sentByName
  const extDataJson = JSON.parse(quoteMsg.value.extData)
  const mediaType = extDataJson.mediaType
  const fileName = extDataJson.fileName
  const previewUrl = extDataJson.previewUrl
  const downloadUrl = extDataJson.downloadUrl
  let msgHtml
  if(mediaType){
    if(mediaType.startsWith('image')){// 图片
      msgHtml = `<img style='width: 40px;' src='${previewUrl}'/>`
    }else { // 文件
      msgHtml = `<a href='${downloadUrl}' download='${fileName}' style='color:gray;'>${fileName}</a>`
    }
  }else{
    const textContent = getTextContent(quoteMsg.value.content)
    msgHtml = textContent
  }
  return `${sentByName}: ${msgHtml}`
})
const getTextContent = htmlString => {
  // 创建一个虚拟的DOM元素
  let tempElement = document.createElement('div');
  tempElement.innerHTML = htmlString;  // 设置HTML内容
  // 获取纯文本
  let textOnly = tempElement.textContent || tempElement.innerText;
  console.log('textOnly: ',textOnly);  // 输出：Hello world!
  return textOnly
}
// 右键消息处理事件
const handleMsgRightClick = (event, msg) => {
  // event.preventDefault();
  rcMsgMenuPosition.value = {
      x: event.clientX,
      y: event.clientY
  }
  const rcMenuBoxWidth = 80; // 右击菜单宽度
  const screenWidth = window.innerWidth;  // 获取窗口的宽度
  // 确保菜单不会超出屏幕右侧
  if (rcMsgMenuPosition.value.x + rcMenuBoxWidth > screenWidth) {
    rcMsgMenuPosition.value.x = screenWidth - rcMenuBoxWidth - 15;
  }

  rcMsg.value = msg
  rcMsgMenuVisible.value = true
}
// 处理点击空白处事件
const handleRcMsgOutside = event => {
    // 检查点击事件的目标元素（event.target）是否位于 menu 元素内部
    if(rcMsgMenuRef.value && !rcMsgMenuRef.value.contains(event.target)){
      rcMsgMenuVisible.value = false
    }
}
const addRcMsgOutsideListener = () => {
  document.addEventListener('click', handleRcMsgOutside)
}
const removeRcMsgOutsideListener = () => {
  document.removeEventListener('click', handleRcMsgOutside)
}
// 处理消息引用
const handleMsgQuote = () => {
  // console.log('handleMsgQuote:', rcMsg.value);
  quoteMsg.value = rcMsg.value
  rcMsgMenuVisible.value = false
  setMessageInputFocus()
}
const quoteMsgBoxRef = ref(null)
const handleClickQuoteMsgBox = () => {
  // console.log('handleClickQuoteMsgBox');
  const images = quoteMsgBoxRef.value.querySelectorAll('img');
  // console.log('images: ', images[0].getAttribute('src'));
  if(images && images.length > 0){
    previewOneImage(images[0].getAttribute('src'))
  }
}
const handleClickQuoteMsgBox2 = event => {
  console.log('handleClickQuoteMsgBox2-event:',event);
  const target = event.target;
  if (target.tagName.toLowerCase() === 'img') {
    const imageSrc = target.getAttribute('src');
    previewOneImage(imageSrc);
  }
}
// 处理消息复制
const handleMsgCopy = () => {
  // navigator.clipboard.writeText(rcMsg.value.content) // 写到粘贴板（这个只能在localhost或者https环境下使用）
  const textArea = document.createElement('textarea');
  textArea.value = rcMsg.value.content;
  document.body.appendChild(textArea);
  textArea.select();
  document.execCommand('copy');
  document.body.removeChild(textArea);
  rcMsgMenuVisible.value = false
}

// 处理文件另存为
const handleFileSaveAs = () => {
  console.log('handleFileSaveAs:', rcMsg.value);
  const extDataJson = JSON.parse(rcMsg.value.extData)
  const downloadUrl = extDataJson.downloadUrl
  window.location.href = downloadUrl; 
  rcMsgMenuVisible.value = false
}



// 聊天记录查询
const openChmDrawer = ref(false)
const chmListBoxRef = ref()
const chmList = ref([])
const chmQo = ref({
  roomId:'',
  kw:'',
  msgType:'',
  startTime:'',
  endTime:'',
  pageSize:5000,
  excluSysMsg:1
})
const showChmDrawer = () => {
  chmQo.value.roomId = RoomState.currentRoom.id
  openChmDrawer.value = true
}
const closeChmDrawer = () => {
  chmQo.value.roomId = ''
  chmQo.value.kw = ''
  chmQo.value.msgType = ''
  chmQo.value.startTime = ''
  chmQo.value.endTime = ''
  openChmDrawer.value = false
}



// 群公告
const openRoomBulletinDrawer = ref(false)
const isRbdEdit = ref(false)
const rbText = ref('')
const showRbEditDialog = () => {
  console.log('showRbEditDialog')
  rbText.value = RoomState.currentRoom.roomBulletin
  isRbdEdit.value = true
}
const closeRbEditDialog = () => {
  console.log('closeRbEditDialog')
  rbText.value = ''
  isRbdEdit.value = false
}
const doSaveRbEdit = async () => {
  const param = {
    roomId:RoomState.currentRoom.id,
    roomBulletin:rbText.value
  }
  
  const res = await $post(RoomApi.updById, param)
  if(!res.success){
    return $msg_e(res.message)
  }
  $msg_s('保存成功')
  RoomState.currentRoom.roomBulletin = rbText.value
  rbText.value = ''
  isRbdEdit.value = false
}

const handleRbDrawerClick = event => {
  if (event.target && event.target.tagName === 'IMG') {
      let url = event.target.src
      previewOneImage(url)
  }
}



// 截图
const screenshotStatus = ref(false)
const openScreenShot = () => {
  screenshotStatus.value = true
}
const getImg = async imgBase64 => {
  // console.log('screenshot-base64:',imgBase64);
  const file = base64ToFile(imgBase64)
  console.log('screenshot-file:',file)
  const formData = new FormData()
  formData.append('file', file)
  formData.append('bizType', 'chat_file')
  formData.append('bizId', RoomState.currentRoom.id + ',' + UserState.loginUser.id)
  const res = await $post(AttachmentApi.upload, formData, {
    headers:{
      'Content-Type': 'multipart/form-data',
      'x-auth-token': window.localStorage.getItem('token')
    }
  })
  console.log('screenshot-upload-res: ', res)
  if(!res.success){
    return $msg_e(res.message)
  }
  sendFileMessage(res.data, file)
}
const destroyComponent = () => {
  screenshotStatus.value = false
}
const base64ToFile = base64Str => {
  const arr = base64Str.split(',')
  const mime = arr[0].match(/:(.*?);/)[1]
  const bstr = atob(arr[1])
  let n = bstr.length
  const u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new File([u8arr], 'screenshot', { type: mime })
}

const doRemindUser = user => {
  message.value = message.value + '@' + user.username
}

// 查询聊天记录
watch(chmQo, async newVal => {
  // console.log('chmQo:',newVal);
  const params = {
    roomId: newVal.roomId,
    kw: newVal.kw,
    msgType: newVal.msgType,
    startTime: newVal.startTime ? newVal.startTime + ' 00:00:00' : '',
    endTime: newVal.endTime ? newVal.endTime + ' 23:59:59' : '',
    pageSize: newVal.pageSize,
    excluSysMsg: newVal.excluSysMsg
  }
  chmList.value = await getChatMessage(params)
},{deep:true})


watch(rcMsgMenuVisible, newVal => {
  if(!newVal){
    rcMsg.value = null
    rcMsgMenuRef.value = null
    rcMsgMenuPosition.value = {x:0,y:0}
  }
})

// 侦听创建群组的对话框关闭
watch(openEditGroupComponent, (newVal, oldVal) => {
  // console.log(newVal, oldVal);
  // 有打开到关闭
  if(oldVal && !newVal) getRoomList()
})

watch(editGroupComponentMode, (newVal, oldVal) => {
  // console.log(newVal, oldVal);
  // 有打开到关闭
  if(oldVal==='edit'){
    // console.log('xxx');
    showGroupUserDrawer()
  }
})


watch(newMsgCount, newVal => {
  RoomState.currentRoom.unreadMsgCount = newVal
})

watch(() => RoomState.currentRoom, newVal => {
  // console.log('currentRoom发生变更:'+JSON.stringify(newVal));
  if(RoomState.currentRoom.id){
    roomMap.value.set(RoomState.currentRoom.id, RoomState.currentRoom)
    initLoadChatMsg()
  }
})

/**处理接收新消息时浏览器通知行为 */
const handleNewMsgBrowserNotify = msg => {
  if(msg.msgType===0) return
  
  if(!isPageFocus.value){
    // 修改document.title
    document.title = '您有一条新消息!'

    // 发送浏览器通知
    if (Notification.permission === "granted") {
      let title = '飞信新消息提醒'
      let simpleText = msg.simpleText?.length > 30 ? msg.simpleText.slice(0, 30) + '...' : msg.simpleText;
      new Notification(title, {
        body: msg.sentByName + ': ' + simpleText
      });
    } else {
      console.log("没有权限显示通知");
    }
  }
}


const isPageFocus = ref(true)

window.onfocus = () => {
  // console.log('页面聚焦')
  isPageFocus.value = true
  document.title = 'Chat'
}

window.onblur = () => {
  // console.log('离开页面')
  isPageFocus.value = false
}


// 生命周期
onMounted(()=>{
  getRoomList()
  initLoadChatMsg()
  initSocketListener()
  addRcMsgOutsideListener()
  setMessageInputFocus()
})

onBeforeUnmount(() => {
  removeRcMsgOutsideListener()
})



</script>

<style scoped lang="scss">
.chat-container{
  height: 100%;
  display: flex;
  flex-direction: row; /**主轴是从左到由 */
  .left{
    width: 220px;
    padding: 5px;
    display: flex;
    flex-direction: column; /**主轴是从上到下 */
    .top-box{
      display: flex;
      flex-direction: row; /**主轴是从左到右 */
      align-items: center;
      .create-group{
        width: 32px;
        height: 32px;
        border-radius: 2px;
        margin-left: 6px;
        background-color: #E5E5E7;
        display: flex;
        justify-content: center;
        align-items: center;
        cursor: pointer;
        & > .el-icon{
          font-size: 16px;
        }
      }
      .create-group:hover{
        background-color: #CFD0D2;
      }
      .search{
        flex: 1;
      }
      
    }
    & > .room-list{
      height: 100%;
      display: flex;
      flex-direction: column;
    }
  }
  .right{
    flex: 1;
    padding: 5px 5px 5px 0px;
    box-sizing: border-box;/**当设置了padding时需要再设置box-sizing:border-box，不然会出现滚动条 */
    height: 100%;
    width: 100%;
    overflow-y: hidden; /**隐藏超出部分，不显示滚动条。 */
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    & > .title-box{
      height: 40px;
      border-bottom: 1px solid #e2e1e4;
      & > .chat-title{
        height: 100%;
      }
      & > .private-chat-title{
        display: flex;
        flex-direction: column;
        & > div{
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
        }
        & > .up{
          height: 80%;
          font-size: 14px;
        }
        & > .down{
          flex: 1;
          margin-bottom: 5px;
          color: gray;
          font-size: 12px;
          display: flex;
          flex-direction: row;
          justify-content: center;
          align-items: center;
          & > .state{
            --diameter: 8px;
            width: var(--diameter);
            height: var(--diameter);
            border-radius: 50%;
            margin-right: 6px
          }
        }
      }
      & > .group-chat-title{
        display: flex;
        flex-direction: row;
        justify-content: center;
        align-items: center;
      }
    }
    & > .message-box{
      flex: 1;
      overflow-y: hidden;/**父元素限制滚动 */
      position: relative;/**开启定位，给下面tip-box绝对定位作参照用 */
      & > .loading{
        font-size: 10px;
        text-align: center;
        color: red;
      }
      & > .chat-message-box{
        height: 100%;
        background-color: #F5F5F5;
        // 此处改为使用<msg-item组件>……
        /**
        & > .msg-item{
          display: flex;
          flex-direction: column;
          margin-bottom: 10px;
          & > .title{
            display: flex;
            margin-bottom: 2px;
            & > div{
              display: flex;
              flex-direction: column;
              justify-content: end;
            }
            & > .user{
              font-size: 14px;
              color: #FF6347;
              margin: 0px 5px;
            }
            & > .time{
              font-size: 8px;
              color: lightgray;
              padding-bottom: 1.5px;
            }
          }
          & > .content{
            display: flex;
            // 通过:style动态设置主轴方向，是自己发的消息统一靠右，否则靠左
            & > .content-detail{
              display: inline-block;
              max-width: 60%;
              margin: 0 5px;
              padding: 3px;
              border-radius: 3px;
              font-size: 14px;
            }
          }
          & > .sys-msg-content{
            display: flex;
            flex-direction: row;
            justify-content: center;
            align-items: center;
            & > span{
              font-size: 10px;
              color: gray;
            }
          }
          & > .quote-msg-content{
            padding: 3px 5px;
            display: flex;
            font-size: 12px;
            & .quote-content-detail{
              padding: 5px;
              background-color: #E8E8E8;
              color: #797979;
              max-width: 400px;
              border-radius: 1.5px;
            }
          }

        }
        */
      }
      
      & > .tip-box{
        background-color: #FFD700;
        width: 90px;
        height: 20px;
        border-radius: 10px;
        position: absolute;/**开启绝对定位，相对于最近的开启了定位或者文档的html进行定义，注意要放到可以滚动的外面才行 */
        bottom: 5px;/**通过bottom、right结合定位到右下角 */
        right: 20px;
        display: flex;/**让tip-box中的文字上下左右居中 */
        flex-direction: row;
        justify-content: center;
        align-items: center;
        cursor: pointer;
      }
    }
    & > .v-resizer{
      height: 5px;
      cursor: n-resize;
    }
    & .input-box{
      height: 220px;
      border: 1px solid lightgray;
      display: flex;
      flex-direction: column;
      border-radius: 5px;
      /**输入框顶部菜单行样式 */
      & > .menu-list-box{
        display: flex;
        flex-direction: row;
        justify-content: space-between;
        & > .btn-box{
          padding: 0px 5px;
          display: flex;
          flex-direction: row;/**主轴从左到右 */
          align-items: center;/**垂直方向居中 */
        }
        & > .left-btn{
          justify-content: start;/**靠左 */
          display: flex;
          flex-direction: row;
          justify-content: start;
          gap: 10px;
          & > .item{
            font-size: 16px;/**控制icon大小 */
            height: 100%;
            display: flex;/**设置item中的图标居中 */
            justify-content: center;
            align-items: center;
            & > .el-tooltip__trigger{
              display: flex;/**内嵌了<el-upload>组件的图标通过这里设置居中 */
              justify-content: center;
              align-items: center
            }
            & .el-icon{
              cursor: pointer;
            }
            & .el-icon:hover{
              color: lightgreen;
            }
          }
          
        }
        & > .right-btn{
          justify-content: end;/**靠右 */
          padding: 5px 5px 0px 0px;
        }
      }
      /**引用消息展示区 */
      & > .quote-msg-box{
        display: flex;
        flex-direction: row;
        padding: 0px 5px;
        & > span{
          background-color: lightgray;
          color: gray;
          padding: 5px;
          max-width: 400px;

        }
        & > .el-icon{
          background-color: lightgray;
          height: 100%;
          font-size: 16px;
          color: red;
          cursor: pointer;
        }
      }
      /**输入框 */
      & > .message-input-box{
        flex: 1;
        // 在下面统一设置
        // :deep(.el-textarea__inner){ /**改变组件内部输入时文字的颜色，注意deep内不要加& */
        //   color: black;
        // }
      }
    }
    
  }
}

/**强行穿透渲染组件内部的样式 */
:deep(.el-textarea__inner){
  height: 100% !important;
  border: none !important;
  box-shadow: none !important;
  padding: 5px !important;
  overflow-y: auto;
  color: black;
  &::-webkit-scrollbar{
      width: 2px; /* 设置滚动条的宽度 */
      height: 2px; /* 设置滚动条的高度 */
  }
  &::-webkit-scrollbar-thumb {
      background-color: #DCDCDC; /* 设置滚动条滑块的颜色 */
      border-radius: 2px; /* 设置滚动条滑块的圆角 */
  }
  &::-webkit-scrollbar-track {
      background-color: #fff; /* 设置滚动条轨道的颜色 */
      border-radius: 2px; /* 设置滚动条轨道的圆角 */
  }
}


/**群成员抽屉样式 */
:deep(.group-user-drawer .el-drawer__header){
  margin-bottom: 0px;
}
.group-user-container{
  height: 100%;/**限制外层div不能超长 */
  overflow-y: hidden;
  & > .group-user-list{
    height: 100%;/**内存集成父层的高度 */
    display: flex;
    flex-direction: column;
    & > .item{
      // margin-bottom: 2px;
      & > .user-info{
        display: flex;
        flex-direction: row;
        justify-content: space-between;
        align-items: center;
        & > .left{
          display: flex;
          flex-direction: row;
          justify-content: start;
          align-items: center;
          flex: 1;
          & > .lc-avatar{
            margin-right: 4px;
          }
          & > span{
            font-size: 14px;
          }
        }
        & > .right{
          display: flex;
          flex-direction: row;
          justify-content: end;
          align-items: center;
          gap: 4px;
          & .item{
            cursor: pointer;
            font-size: 16px;
          }
          & .item.tip-opt{
            color: lightsalmon
          }
          & .item.send-msg{
            color: lightgreen;
          }
          & .item.user-info{
            color: lightblue;
          }
        }
        
      }
    }
  }
}


/**消息右键菜单 */
.rc-msg-menu{
    display: flex;
    flex-direction: column;
    justify-content: start;
    width: 80px;
    position: absolute;
    z-index: 3000;
    background-color: #fff;
    padding: 5px;
    border: 1px solid lightgray;
    box-sizing: border-box;
    border-radius: 5px;
    & > .rc-msg-menu-item{
        height: 25px;
        display: flex;
        flex-direction: row;
        justify-content: start;
        align-items: center;
        padding-left: 10px;
        cursor: pointer;
        &:hover{
          background-color: lightgray;
        }
    }
}

/**聊天记录抽屉框 */
:deep(.chm-drawer .el-drawer__body){/**修改内部的样式 */
  padding:0px;
}
.chm-container{
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow-y: hidden;
  & > .custom-header{
    background-color: #F7F7F7;
    padding: 10px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    & > .up{
      display: flex;
      flex-direction: row;
      justify-content: center;
      align-items: center;
      gap: 5px;
      & > .el-input{
        max-width: 300px;
      }
      & > .el-icon{
        font-size: 16px;
        color: red;
      }
    }
    & > .down{
      display: flex;
      flex-direction: row;
      justify-content: center;
      align-items: center;
      gap: 10px;
      flex-wrap: wrap;
      & > .item{
        font-size: 14px;
        white-space: nowrap;
        padding: 1px;
      }
    }
  }
  & > .chm-list{
    /**这里使用了beautify-scrollbar进行滚动条美化 */
    flex: 1;
    display: flex;
    flex-direction: column;
  }
}

/**群公告样式 */
:deep(.room-bulletin-drawer) {
  --el-drawer-padding-primary: 10px;
}
:deep(.room-bulletin-drawer .el-drawer__header) {
  margin-bottom: 0;
}
:deep(.room-bulletin-drawer .el-drawer__body) {
  padding: var(--el-drawer-padding-primary);
}
.room-bulletin-container{
  height: 100%;
  overflow-y: hidden;
  & > .room-bulletin{
    height: 100%;
    white-space: pre-wrap; /* 保留空格和换行符 */
    font-family: monospace; /* 使用等宽字体 */
  }
}

/**群公告编辑对话框相关样式 */
.rb-edit-container{
  height: 60vh;
}
:deep(.rb-edit-dialog .el-dialog__header){
  padding-bottom: 0px;
}
.rb-edit-dialog-header{
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  & > .el-dialog__title{
    font-size: 14px;
  }
  & > .btn{
    display: flex;
    flex-direction: row;
    justify-content: end;
    align-items: center;
    gap: 10px;
    & > span{
      cursor: pointer;
    }
    & > span:hover{
      background-color: lightgray;
    }
  }
}
</style>